########################################################################
#  Wiizard - A Wii games manager
#  Copyright (C) 2023  CYBERDEViL
#
#  This file is part of Wiizard.
#
#  Wiizard is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  Wiizard is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
########################################################################


import time
import os

from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtCore import Qt, pyqtSignal, QObject

from wiizard import globals as Global
from wiizard.thread import AbstractThread, THREAD_FLAG_IS_CANCELLABLE
from wiizard.scrapers.common import ScraperError, ImgRequestProperties
from wiizard.requestHandler import ImageDownloadException
from wiizard.const import (
  IMG_FRONT_COVER,
  IMG_FRONT_3D_COVER,
  IMG_DISC
)
from wiizard.models.settings import GameImageSettings


class AppResources:
  """ For application icons and images
  """
  ICONS_PATH  = ""
  IMAGES_PATH = ""
  ICONS       = {}
  IMAGES      = {}

  @staticmethod
  def resolvePaths():
    AppResources.findIconsPath()
    AppResources.findImagesPath()

  @staticmethod
  def findIconsPath():
    testFile  = "wiizard_icon_32.png"
    testPaths = [
      os.path.join(os.path.dirname(os.path.abspath(__file__)), "images/"),
      "/usr/share/icons/wiizard/",
      "/usr/local/share/icons/wiizard/",
      os.path.expanduser("~/.local/share/icons/wiizard/")
    ]

    for path in testPaths:
      if os.path.exists(os.path.join(path, testFile)):
        AppResources.ICONS_PATH = path
        return path

    print("WARNING: Were unable to find icons location.")
    return None

  @staticmethod
  def getIcon(iconName):
    if iconName not in AppResources.ICONS:
      filepath = os.path.join(AppResources.ICONS_PATH, iconName)
      icon     = QIcon(QPixmap(filepath))
      AppResources.ICONS.update({iconName: icon})

    return AppResources.ICONS[iconName]

  @staticmethod
  def findImagesPath():
    testFile  = "default_2d_cover.png"
    testPaths = [
      os.path.join(os.path.dirname(os.path.abspath(__file__)), "images/"),
      "/usr/share/wiizard/",
      "/usr/local/share/wiizard/",
      os.path.expanduser("~/.local/share/wiizard/")
    ]

    for path in testPaths:
      if os.path.exists(os.path.join(path, testFile)):
        AppResources.IMAGES_PATH = path
        return path

    print("WARNING: Were unable to find images location.")
    return None

  @staticmethod
  def getImagePath(imageName):
    return os.path.join(AppResources.IMAGES_PATH, imageName)


class _SharedGameImages(QObject):
  """ - these are cached on disk (The images, not the pixmap..)
      - for having only one pixmap in ram per game image
      - for having unified images in all views (img cover type and size)
  """
  changed     = pyqtSignal()

  SIZE_LARGE  = 160
  SIZE_MEDIUM =  96
  SIZE_SMALL  =  48

  def __init__(self):
    QObject.__init__(self)
    self.__imgWidth    = self.SIZE_LARGE
    self.__imgType     = IMG_FRONT_3D_COVER
    self.__gamePixmaps = {}
    self.__games       = []  # id6Strs (for what games this class has available images)
    self.remakePixmaps()

  @property
  def imgType(self):
    return self.__imgType

  def setImgSize(self, size):
    self.__imgWidth = size
    self.remakePixmaps()

  def setImgType(self, imgType):
    self.__imgType = imgType
    self.remakePixmaps()

  def getGameImage(self, id6Str):
    return self.__gamePixmaps[id6Str]

  def addGames(self, id6StrList):
    for id6Str in id6StrList:
      if id6Str not in self.__games:
        self.__addGameImage(id6Str)
        self.__games.append(id6Str)

  def __addGameImage(self, id6Str):
    path = Global.ImageCache.getImage(id6Str, self.__imgType)
    if path is None:
      self.__gamePixmaps.update({id6Str: self.defaultPixmap})
    else:
      width = self.__imgWidth
      pixmap = QPixmap(path).scaledToWidth(width, Qt.SmoothTransformation)
      self.__gamePixmaps.update({id6Str: pixmap})

  def remakePixmaps(self):
    self.defaultPixmap = None
    self.__gamePixmaps.clear()

    if self.__imgType is None:
      self.changed.emit()
      return

    defaultMap = {
      IMG_FRONT_COVER   : AppResources.getImagePath("default_2d_cover.png"),
      IMG_FRONT_3D_COVER: AppResources.getImagePath("default_3d_cover.png"),
      IMG_DISC          : AppResources.getImagePath("default_disc_cover.png")
    }

    width = self.__imgWidth
    self.defaultPixmap = QPixmap(defaultMap[self.__imgType]).scaledToWidth(width, Qt.SmoothTransformation)

    for id6Str in self.__games:
      self.__addGameImage(id6Str)

    self.changed.emit()


class DlImagesThread(AbstractThread):
  progress  = pyqtSignal(int)

  def __init__(self, dlList, requestHandler, scraper):
    AbstractThread.__init__(self, flags=THREAD_FLAG_IS_CANCELLABLE)
    self.__dlList         = dlList
    self.__requestHandler = requestHandler
    self.__scraper        = scraper
    self.failed           = []

  def run(self):
    dlList     = self.__dlList
    scraper    = self.__scraper
    progress   = 0

    for id6Str in dlList:

      try:
        imageLinks = self.__scraper.getGameImageLinks(id6Str)
      except ScraperError as err:
        print(err)
        continue

      imgTypeFlags = 0
      for imgType in dlList[id6Str]:
        imgTypeFlags |= imgType

      languages         = GameImageSettings.getLanguages()
      requestProperties = ImgRequestProperties(imgTypeFlags,
                                               languages=languages)
      gameImageLinks = scraper.selectImages(imageLinks, requestProperties)

      if not gameImageLinks:
        if id6Str not in self.failed:
          self.failed.append(id6Str)
        time.sleep(1)
        continue

      for gameImageLink in gameImageLinks:
        imgPath = Global.ImageCache.getImagePath(id6Str, gameImageLink.type)

        try:
          self.__requestHandler.downloadImage(gameImageLink.url, imgPath)
        except ImageDownloadException as err:
          print(err)  # TODO note the failed for feedback?
          progress += 1
          continue

        print(" -- Downloaded", imgPath)
        if self.cancelled is True:
          break

        progress += 1
        self.progress.emit(progress)

        time.sleep(1)

      if self.cancelled is True:
        break

    self.completed.emit()
